package com.baitiaojun.video.service.impl;

import com.baitiaojun.api.domain.moments.UserMomentsStatus;
import com.baitiaojun.api.domain.user.UserInfo;
import com.baitiaojun.api.domain.video.Tag;
import com.baitiaojun.api.domain.video.Video;
import com.baitiaojun.api.domain.video.VideoComment;
import com.baitiaojun.api.domain.video.VideoTag;
import com.baitiaojun.api.exception.ConditionException;
import com.baitiaojun.api.util.AESUtil;
import com.baitiaojun.api.util.ConstantUtil;
import com.baitiaojun.api.util.SnowFlakeUtil;
import com.baitiaojun.api.vo.JsonRes;
import com.baitiaojun.video.config.AsyncConfig;
import com.baitiaojun.video.feign.ElasticsearchVideoFeign;
import com.baitiaojun.video.feign.MomentsFeign;
import com.baitiaojun.video.feign.UserFeign;
import com.baitiaojun.video.mapper.TagMapper;
import com.baitiaojun.video.mapper.VideoMapper;
import com.baitiaojun.video.mapper.VideoTagMapper;
import com.baitiaojun.video.service.*;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.mahout.cf.taste.common.TasteException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @类名 VideoServiceImpl
 * @描述 TODO
 * @作者 白条君
 * @创建日期 2022/12/19 13:15
 * @版本 1.0
 */
@Service
public class VideoServiceImpl implements VideoService {

    @Autowired
    private UserFeign userFeign;

    @Autowired
    private ElasticsearchVideoFeign elasticsearchVideoFeign;

    @Resource
    private VideoMapper videoMapper;

    @Resource
    private TagMapper tagMapper;

    @Resource
    private VideoTagMapper videoTagMapper;

    @Lazy
    @Autowired
    private VideoRecommendService recommendService;

    @Lazy
    @Autowired
    private VideoParentCommentService videoParentCommentService;

    @Autowired
    private MomentsFeign momentsFeign;

    @Autowired
    private VideoLikeService videoLikeService;

    @Autowired
    private VideoViewService videoViewService;

    @Autowired
    private AsyncConfig asyncConfig;

    @Transactional
    @Override
    public Long addVideo(Video video) throws Exception {
        //对url解密
        AESUtil aesUtil = AESUtil.lazyGetAesUtil();
        video.setThumbnail(aesUtil.decrypt(video.getThumbnail().replace(" ", "+")));
        video.setUrl(aesUtil.decrypt(video.getUrl().replace(" ", "+")));
        Long videoId = SnowFlakeUtil.getNextId();
        video.setId(videoId);
        video.setCreatetime(new Date());
        //添加视频
        int resVideo = videoMapper.insertSelective(video);
        if (resVideo == 0) {
            throw new ConditionException("视频添加失败");
        }
        List<Tag> tags = video.getTags();
        if (!tags.isEmpty()) {
            List<VideoTag> videoTags = new ArrayList<>();
            tags.forEach(tag -> {
                //前端传递过来的tag列表初始化其他信息进行添加
                Long tagId = SnowFlakeUtil.getNextId();
                Date createTime = new Date();
                tag.setId(tagId);
                tag.setCreatetime(createTime);
                //添加video-tag关联信息
                videoTags.add(VideoTag.builder().id(SnowFlakeUtil.getNextId())
                        .videoid(videoId)
                        .tagid(tagId)
                        .createtime(createTime)
                        .build());
            });
            //添加视频标签关联信息
            int resTag = tagMapper.batchInsertTags(tags);
            if (resTag != tags.size()) {
                throw new ConditionException("标签添加失败");
            }
            //添加视频标签
            int resVideoTag = videoTagMapper.batchInsertVideoTags(videoTags);
            if (resVideoTag != videoTags.size()) {
                throw new ConditionException("视频标签关联关系添加失败");
            }
        }
        //添加动态状态
        UserMomentsStatus momentsStatus = new UserMomentsStatus();
        momentsStatus.setId(SnowFlakeUtil.getNextId());
        momentsStatus.setTrycount(0);
        momentsStatus.setStatus(ConstantUtil.DEFAULT_STATUS);
        momentsStatus.setCreatetime(new Date());
        momentsStatus.setUserid(video.getUserId());
        momentsStatus.setContentid(videoId);
        JsonRes jsonRes = momentsFeign.addMomentsStatus(momentsStatus);
        if (jsonRes.get("status").equals(500)) {
            throw new ConditionException((String) jsonRes.get("msg"));
        }
        return videoId;
    }

    @Async
    public void asyncPublishMoments(Long videoId, Video video) {
        momentsFeign.publishMoments(videoId, video.getUserId());
    }

    @Override
    public Integer isExistsVideo(Long videoId) {
        return videoMapper.isExistsVideo(videoId);
    }

    @Override
    public Video getVideoById(Long videoId) {
        return videoMapper.selectByPrimaryKey(videoId);
    }

    @Override
    public Map<String, Object> getVideoDetails(Long videoId) throws Exception {
        Video video = videoMapper.selectByPrimaryKey(videoId);
        if (ObjectUtils.isEmpty(video)) {
            throw new ConditionException("该视频不存在");
        }
        Set<Long> tagIds = videoTagMapper.selectTagIdsByVideoId(video.getId());
        if (tagIds.size() > 0) {
            List<Tag> tagNames = tagMapper.batchSelectByTagIds(tagIds);
            video.setTags(tagNames);
        }
        ThreadPoolExecutor executor = asyncConfig.getAsyncExecutor();
        if (ObjectUtils.isEmpty(executor)) {
            throw new ConditionException("无法获取线程池执行器");
        }
        CountDownLatch latch = new CountDownLatch(3);
        //添加点赞个数
        UserInfo userInfo = userFeign.batchGetUserInfoByUserIdsSet(Sets.newHashSet(video.getUserId())).get(0);
        executor.execute(() -> {
            Integer count = (Integer) videoLikeService.getVideoLike(userInfo.getUserid(), videoId).get("count");
            video.setLickCount(count);
            latch.countDown();
        });
        //添加观看次数
        executor.execute(() -> {
            Integer viewCount = videoViewService.getVideoViewCount(videoId);
            video.setViewCount(viewCount);
            latch.countDown();
        });
        //添加评论次数
        executor.execute(() -> {
            List<VideoComment> videoComments = videoParentCommentService.batchVideoCommentCount(Sets.newHashSet(videoId));
            if (ObjectUtils.isNotEmpty(videoComments)) {
                video.setCommentCount(videoComments.get(0).getCount());
            } else {
                video.setCommentCount(0);
            }
            latch.countDown();
        });
        //加密文件url
        AESUtil aesUtil = AESUtil.lazyGetAesUtil();
        video.setUrl(aesUtil.encrypt(video.getUrl()));
        video.setThumbnail(aesUtil.encrypt(video.getThumbnail()));
        video.setUserId(null);
        //添加头像
        userInfo.setAvatar(aesUtil.encrypt(userInfo.getAvatar()));
        userInfo.setGender(null);
        userInfo.setUserid(null);
        latch.await();
        Map<String, Object> result = new HashMap<>();
        result.put("userInfo", userInfo);
        result.put("video", video);
        return result;
    }

    @Override
    public List<Video> getHomePageVideo(Long userId, Long lastId, Integer pageSize) throws Exception {
        ThreadPoolExecutor executor = asyncConfig.getAsyncExecutor();
        if (ObjectUtils.isEmpty(executor)) {
            throw new ConditionException("无法获取线程池执行器");
        }
        CountDownLatch latch = new CountDownLatch(2);
        List<Video> videos = new ArrayList<>();
        AtomicInteger size = new AtomicInteger(0);
        executor.execute(() -> {
            try {
                if (ObjectUtils.isNotEmpty(userId)) {
                    List<Video> recommend = recommendService.recommend(userId);
                    if (ObjectUtils.isNotEmpty(recommend)) {
                        size.set(recommend.size());
                        videos.addAll(recommend);
                    }
                }
            } catch (TasteException | InterruptedException | ConditionException e) {
                e.printStackTrace();
            }
            latch.countDown();
        });
        AtomicReference<Long> reference = new AtomicReference<>(lastId);
        executor.execute(() -> {
            try {
                Long id = reference.get();
                if (ObjectUtils.isEmpty(id)) {
                    id = 0L;
                }
                List<Video> pageHomeVideoList = elasticsearchVideoFeign.getPageHomeVideoList(id, pageSize - size.get());
                pageHomeVideoList = pageHomeVideoList.stream()
                        .sorted((video1, video2) -> video2.getViewCount().compareTo(video1.getViewCount()))
                        .collect(Collectors.toList());
                videos.addAll(pageHomeVideoList);
            } catch (IOException e) {
                e.printStackTrace();
            }
            latch.countDown();
        });
        latch.await();
        return videos;
    }

    @Override
    public List<Long> getVideoIds() {
        return videoMapper.selectVideoIds();
    }

    @Transactional
    @Override
    public void removeVideo(Long videoId) throws ConditionException {
        int resVideoTag = videoTagMapper.batchDeleteVideoTags(videoId);
        if (resVideoTag == 0) {
            throw new ConditionException("删除视频tag失败");
        }
        int resVideo = videoMapper.batchDeleteVideo(videoId);
        if (resVideo == 0) {
            throw new ConditionException("删除视频记录失败");
        }
    }

    @Override
    public Long getUserIdByVideoId(Long videoId) {
        return videoMapper.selectUserIdByVideoId(videoId);
    }
}